/* linkit.js
 * By François Leporcq
 * MIT Licensed.
 */
var AbstractLink = Composite.extend({
    _className: "AbstractLink",
    setStartPolygon: function(startPolygon){
        if(this._startPolygon != null){
            this._startPolygon.setPartOfComposite(false);
        }
        this._startPolygon = startPolygon;
        this._startPolygon.setPartOfComposite(true);
        this._updateStartPolygon();
    },
    setEndPolygon: function(endPolygon){
        if(this._endPolygon != null){
            this._endPolygon.setPartOfComposite(false);
        }
        this._endPolygon = endPolygon;
        this._endPolygon.setPartOfComposite(true);
        this._updateEndPolygon();
    },
    setStartLabel: function(startLabel){
        if(this._startLabel != null){
            this._startLabel.setPartOfComposite(false);
        }
        this._startLabel = startLabel;
        this._startLabel.setPartOfComposite(true);
        this._updateStartLabel();
    },
    setEndLabel: function(endLabel){
        if(this._endLabel != null){
            this._endLabel.setPartOfComposite(false);
        }
        this._endLabel = endLabel;
        this._endLabel.setPartOfComposite(true);
        this._updateEndLabel();
    },
    getShapes: function(){
        var shapes = new Array();
        shapes.push(this._line);
        if(this._startPolygon){
            shapes.push(this._startPolygon);
        }
        if(this._endPolygon){
            shapes.push(this._endPolygon);
        }
        if(this._startLabel){
            shapes.push(this._startLabel);
        }
        if(this._endLabel){
            shapes.push(this._endLabel);
        }
        if(this._midLabel){
            shapes.push(this._midLabel);
        }
        return shapes;
    },
    _updateStartPolygon: function(){
        throw new Error("The '_updateStartPolygon()' method must be overrided in '" + this._className + "' class");
    },
    _updateStartLabel: function(){
        if(this._startLabel != null && this._start != null){
            var width = this._startLabel.getWidth();
            var height = this._startLabel.getHeight();
            var x = this._start.getX();
            var y = this._start.getY();
            var cardinalPoint = this._start.getCardinalPoint();
            if(this._end != null){
                var marginX = Workspace.label.margin + width/2;
                var marginY = Workspace.label.margin + height/2;
                var line = new Line(this._start, this._end);
                var thetaX = (360-line.getXAxisTheta()) * Math.PI / 180;
                var thetaY = (90-360-line.getXAxisTheta()) * Math.PI / 180;

                if(cardinalPoint == ECardinalPoint.EAST){
                    x += marginX - (width / 2);
                    y += (Math.tan(thetaX) * marginX) - (height / 2);
                }else if(cardinalPoint == ECardinalPoint.WEST){
                    x -= marginX + (width / 2);
                    y -= (Math.tan(thetaX) * marginX) + (height / 2);
                }else if(cardinalPoint == ECardinalPoint.NORTH){
                    x -= (Math.tan(thetaY) * marginY) + (width / 2);
                    y += marginY - (height / 2);
                }else if(cardinalPoint == ECardinalPoint.SOUTH){
                    x += (Math.tan(thetaY) * marginY) - (width / 2);
                    y -= marginY + (height / 2);
                }
            }
            this._startLabel.setOrigin(new Point(x, y));
        }
    },
    _updateEndLabel: function(){
        if(this._endLabel != null && this._end != null){
            var width = this._endLabel.getWidth();
            var height = this._endLabel.getHeight();
            var x = this._end.getX();
            var y = this._end.getY();
            var cardinalPoint = this._end.getCardinalPoint();
            if(this._start != null){
                var marginX = Workspace.label.margin + width/2;
                var marginY = Workspace.label.margin + height/2;
                var line = new Line(this._start, this._end);

                var thetaX = (360-line.getXAxisTheta()) * Math.PI / 180;
                var thetaY = (90-360-line.getXAxisTheta()) * Math.PI / 180;

                if(cardinalPoint == ECardinalPoint.EAST){
                    x += marginX - (width / 2);
                    y += (Math.tan(thetaX) * marginX) - (height / 2);
                }else if(cardinalPoint == ECardinalPoint.WEST){
                    x -= marginX + (width / 2);
                    y -= (Math.tan(thetaX) * marginX) + (height / 2);
                }else if(cardinalPoint == ECardinalPoint.NORTH){
                    x -= (Math.tan(thetaY) * marginY) + (width / 2);
                    y += marginY - (height / 2);
                }else if(cardinalPoint == ECardinalPoint.SOUTH){
                    x += (Math.tan(thetaY) * marginY) - (width / 2);
                    y -= marginY + (height / 2);
                }
            }
            this._endLabel.setOrigin(new Point(x, y));
        }
    },
    _updateMidLabel: function(){
        if(this._midLabel != null){
            var width = this._midLabel.getWidth();
            var height = this._midLabel.getHeight();
            var origin = new Point();
            if(this._start != null && this._end != null){
                var line = new Line(this._start, this._end);
                var center = line.getBox().getCenter();
                var x = center.getX() - (width / 2);
                var y = center.getY() - (height / 2);
                origin.setX(x);
                origin.setY(y);
            }
            this._midLabel.setOrigin(origin);
        }
    },
    _updateEndPolygon: function(){
        throw new Error("The '_updateEndPolygon()' method must be overrided in '" + this._className + "' class");
    },
    setStart: function(start){
        throw new Error("The 'setStart(Point start)' method must be overrided in '" + this._className + "' class");
    },
    getStart: function(){
        return this._start;
    },
    setEnd: function(end){
        throw new Error("The 'setEnd(Point end)' method must be overrided in '" + this._className + "' class");
    },
    getEnd: function(){
        return this._end;
    },
    setFromShape: function(fromShape){
        this._fromShape = fromShape;
    },
    setToShape: function(toShape){
        this._toShape = toShape;
    },
    getFromShape: function(){
        return this._fromShape;
    },
    getToShape: function(){
        return this._toShape;
    },
    computeStartEnd: function(){
        var toShapeCenter = this._toShape.getCenter();
        var fromShapeCenter = this._fromShape.getCenter();
        var startAnchor = this._fromShape.getAnchor(toShapeCenter);
        var endAnchor = this._toShape.getAnchor(fromShapeCenter);

        //Case of a shape on top of an other shape
        //If a shape has not anchor, we create it on its center
        startAnchor = (startAnchor != null) ? startAnchor : new Anchor(fromShapeCenter.getX(), fromShapeCenter.getY());
        endAnchor = (endAnchor != null) ? endAnchor : new Anchor(toShapeCenter.getX(), toShapeCenter.getY());

        //Case of a shape on top of an other shape
        //If startAnchor OR endAnchor have not cardinal point, we take the opposite point
        if(startAnchor.getCardinalPoint() != null && endAnchor.getCardinalPoint() == null){
            endAnchor.setCardinalPoint(ECardinalPoint.getOpposite(startAnchor.getCardinalPoint()));
        }else if(startAnchor.getCardinalPoint() == null && endAnchor.getCardinalPoint() != null){
            startAnchor.setCardinalPoint(ECardinalPoint.getOpposite(endAnchor.getCardinalPoint()));
        }else if(startAnchor.getCardinalPoint() == null && endAnchor.getCardinalPoint() == null){
            //If startAnchor AND endAnchor have not cardinal point, we compute them
            var
            fromShapeX = this.getFromShape().getCenter().getX(),
            fromShapeY = this.getFromShape().getCenter().getY(),
            toShapeX = this.getToShape().getCenter().getX(),
            toShapeY = this.getToShape().getCenter().getY(),
            deltaX = Math.abs(fromShapeX - toShapeX),
            deltaY = Math.abs(fromShapeY - toShapeY);

            if(deltaX > deltaY){
                if(fromShapeX > toShapeX){
                    startAnchor.setCardinalPoint(ECardinalPoint.WEST);
                    endAnchor.setCardinalPoint(ECardinalPoint.EAST);
                }else{
                    startAnchor.setCardinalPoint(ECardinalPoint.EAST);
                    endAnchor.setCardinalPoint(ECardinalPoint.WEST);
                }
            }else{
                if(fromShapeY > toShapeY){
                    startAnchor.setCardinalPoint(ECardinalPoint.NORTH);
                    endAnchor.setCardinalPoint(ECardinalPoint.SOUTH);
                }else{
                    startAnchor.setCardinalPoint(ECardinalPoint.SOUTH);
                    endAnchor.setCardinalPoint(ECardinalPoint.NORTH);
                }
            }

        }
        this.setStart(startAnchor);
        this.setEnd(endAnchor);
    },
    afterWorkspaceAdd: function(workspace){
        if(this._startLabel){
            this._startLabel._ninjaComputeDimension(workspace);
            this._updateStartLabel();
            this._startLabel._text.afterWorkspaceAdd(workspace);
        }
        if(this._endLabel){
            this._endLabel._ninjaComputeDimension(workspace);
            this._updateEndLabel();
            this._endLabel._text.afterWorkspaceAdd(workspace);
        }
        if(this._midLabel){
            this._midLabel._ninjaComputeDimension(workspace);
            this._updateMidLabel();
            this._midLabel._text.afterWorkspaceAdd(workspace);
        }
    }
}, true);